/* USER CODE BEGIN Header */
/**
 ******************************************************************************
 * File Name          :
 * Description        :
 ******************************************************************************
 * @attention
 *
 *
 ******************************************************************************
 */
/* USER CODE END Header */

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "IIC_Device.h"
#include "stm32g4xx_ll_I2C.h"
#include "stm32g4xx_hal.h"
#include "stm32g4xx_ll_utils.h"
#include "structs.h"
#include "DriverPara.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define EEPROM_ADDR 0xA0
#define EEPROM_ERROR_TIME 10 // 10 times
#define EEPROM_PAGE_SIZE 128
#define BL24C512_PAGE_MAX 127

#define StartPage_Calibration 0
#define PageSize_Calibration 5
#define StartPage_UserParameters 6
#define PageSize_UserParameters 5
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */
extern I2C_HandleTypeDef hi2c1;
extern CRC_HandleTypeDef hcrc;
/* USER CODE END Variables */

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */

/* USER CODE END FunctionPrototypes */

/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */
/*-----------------------------------  BL24C512 -----------------------------------*/
/**
  * @brief read eeprom BL24C512
  * @param uint16_t addr:the starting address of the eeprom
					 uint8_t *recive:the pointer address to which the acquired array from EEPROM is stored
					 uint16_t length:read the length of data
  * @retval
  */
void EEPROM_Read(uint16_t addr, uint8_t *recive, uint16_t length)
{
	HAL_StatusTypeDef result = HAL_ERROR;
	uint8_t error_count = 0;
	while (result != HAL_OK)
	{
		result = HAL_I2C_Mem_Read(&hi2c1, EEPROM_ADDR, addr, 2, recive, length, 1000);

		// EEPROM ERROR FLAG = 1;
		if (error_count >= EEPROM_ERROR_TIME)
		{

			break;
		}
		error_count++;
	}
}

/**
  * @brief write eeprom BL24C512 , single write cann't greater than 128
  * @param uint8_t page_num:the page number
					 uint8_t *load:the array is stored to EEPROM
  * @retval
  */
static void EEPROM_Write_Page(uint8_t page_num, uint8_t *load)
{
	HAL_StatusTypeDef result = HAL_ERROR;
	uint8_t error_count = 0;
	uint16_t addr = 0;

	if (page_num > BL24C512_PAGE_MAX)
		page_num = BL24C512_PAGE_MAX;
	addr = page_num * EEPROM_PAGE_SIZE;

	while (result != HAL_OK)
	{
		result = HAL_I2C_Mem_Write(&hi2c1, EEPROM_ADDR, addr, 2, load, EEPROM_PAGE_SIZE, 1000);

		// EEPROM ERROR FLAG = 1;
		if (error_count >= EEPROM_ERROR_TIME)
		{

			break;
		}
		error_count++;
	}
}

/**
  * @brief Mutipage data write to eeprom BL24C512
  * @param uint8_t start_page:the start page number
					 uint8_t page_num:the page number
					 uint8_t length:the array is stored to EEPROM
  * @retval
  */
static void EEPROM_Write_Multipage(uint8_t start_page, uint8_t page_num, uint8_t *load)
{
	uint8_t page, count;
	page = start_page;
	count = page_num;
	while (count)
	{
		EEPROM_Write_Page(page, load);
		count--;
		page++;
		load += EEPROM_PAGE_SIZE;
		LL_mDelay(5);
	}
}

/**
 * @brief Save array of calibration
 * @param
 * @retval
 */
bool UserPara_Calibration_Save(void)
{
	uint32_t CrcReadCheck = 0;
	uint8_t error_count = 0;
	g_sys.RW.CaliPara.Para.CRCData = HAL_CRC_Calculate(&hcrc,
													   (uint32_t *)g_sys.RW.CaliPara.buffer, sizeof(g_sys.RW.CaliPara.buffer) - 4);

	EEPROM_Write_Multipage(StartPage_Calibration, PageSize_Calibration, g_sys.RW.CaliPara.buffer);
	while (g_sys.RW.CaliPara.Para.CRCData != CrcReadCheck)
	{
		EEPROM_Read(StartPage_Calibration * EEPROM_PAGE_SIZE,
					g_sys.RW.CaliPara.buffer, PageSize_Calibration * EEPROM_PAGE_SIZE);

		CrcReadCheck = HAL_CRC_Calculate(&hcrc, (uint32_t *)g_sys.RW.CaliPara.buffer,
										 sizeof(g_sys.RW.CaliPara.buffer) - 4);

		error_count++;
		if (error_count > EEPROM_ERROR_TIME)
		{
			return false;
		}
	}
	return true;
}

/**
 * @brief Read array of calibration
 * @param
 * @retval
 */
bool UserPara_Calibration_Read(void)
{
	uint8_t error_count = 0;
	uint32_t CrcReadCheck = 0;
	g_sys.RW.CaliPara.Para.CRCData = 1;
	while (g_sys.RW.CaliPara.Para.CRCData != CrcReadCheck)
	{
		EEPROM_Read(StartPage_Calibration * EEPROM_PAGE_SIZE,
					g_sys.RW.CaliPara.buffer, PageSize_Calibration * EEPROM_PAGE_SIZE);

		CrcReadCheck = HAL_CRC_Calculate(&hcrc, (uint32_t *)g_sys.RW.CaliPara.buffer,
										 sizeof(g_sys.RW.CaliPara.buffer) - 4);

		error_count++;
		if (error_count > EEPROM_ERROR_TIME)
		{

			return false;
		}
	}
	return true;
}

/**
 * @brief Save array of UserParameter
 * @param
 * @retval
 */
bool UserPara_UserParameters_Save(void)
{
	uint32_t CrcReadCheck = 0;
	uint8_t error_count = 0;
	g_sys.RW.UserPara.Para.CRCData = HAL_CRC_Calculate(&hcrc,
													   (uint32_t *)g_sys.RW.UserPara.buffer, sizeof(g_sys.RW.UserPara.buffer) - 4);

	EEPROM_Write_Multipage(StartPage_UserParameters, PageSize_UserParameters, g_sys.RW.UserPara.buffer);
	while (g_sys.RW.UserPara.Para.CRCData != CrcReadCheck)
	{
		EEPROM_Read(StartPage_UserParameters * EEPROM_PAGE_SIZE,
					g_sys.RW.UserPara.buffer, PageSize_UserParameters * EEPROM_PAGE_SIZE);

		CrcReadCheck = HAL_CRC_Calculate(&hcrc, (uint32_t *)g_sys.RW.UserPara.buffer,
										 sizeof(g_sys.RW.UserPara.buffer) - 4);

		error_count++;
		if (error_count > EEPROM_ERROR_TIME)
		{
			return false;
		}
	}
	return true;
}
/**
 * @brief Read array of UserParameter
 * @param
 * @retval
 */
bool UserPara_UserParameters_Read(void)
{
	uint8_t error_count = 0;
	uint32_t CrcReadCheck = 0;
	g_sys.RW.UserPara.Para.CRCData = 1;
	while (g_sys.RW.UserPara.Para.CRCData != CrcReadCheck)
	{
		EEPROM_Read(StartPage_UserParameters * EEPROM_PAGE_SIZE,
					g_sys.RW.UserPara.buffer, PageSize_UserParameters * EEPROM_PAGE_SIZE);

		CrcReadCheck = HAL_CRC_Calculate(&hcrc, (uint32_t *)g_sys.RW.UserPara.buffer,
										 sizeof(g_sys.RW.UserPara.buffer) - 4);

		error_count++;
		if (error_count > EEPROM_ERROR_TIME)
		{
			Default_UserParameter(&g_sys.RW.UserPara);
			return false;
		}
	}
	// if there is no frame header,it will write default parameters
	Default_UserParameter(&g_sys.RW.UserPara);

	return true;
}
/*-----------------------------------  BL24C512 END -----------------------------------*/

/**
 * @brief All IIC Device Initialize
 * @param
 * @retval
 */
void IIC_Device_Init(void)
{
	UserPara_Calibration_Read();
	UserPara_UserParameters_Read();
}

/* USER CODE END Application */
